package com.ang.interceptor;

/**
 * @author ssang
 * @date 2022-09-27 15:21
 */
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Objects;
import org.apache.ibatis.executor.Executor;

import javax.annotation.Resource;

/**
 * 数据库更新操作拦截器
 * 一、支持的使用场景
 * ①场景一：通过mybatis-plus BaseMapper自动映射的方法
 * ②场景一：通过mapper接口自定义的方法，更新对象为实体类
 */
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class UpdateInterceptor implements Interceptor {

    @Resource
    private CommonUtil commonUtil;
    /**
     * 使用 @Param("crypt")注解的参数（只支持自定义对象 且同时添加CryptEntity和CryptField注解）
     */
    private static final String paramVal = "crypt";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //代理类方法参数，该拦截器拦截的update方法有两个参数args = {MappedStatement.class, Object.class}
        Object[] args = invocation.getArgs();
        //获取方法参数
        MappedStatement mappedStatement = (MappedStatement) args[0];
        Object parameter = args[1];
        if (Objects.isNull(parameter)) {
            //无参数，直接放行
            return invocation.proceed();
        }
        // 如果是多个参数或使用Param注解（Param注解会将参数放置在ParamMap中）
        if (parameter instanceof MapperMethod.ParamMap) {
            Map paramMap = (Map) parameter;
            if (paramMap.containsKey(paramVal)) {
                Object updateParameter = paramMap.get(paramVal);
                if (commonUtil.needToCrypt(updateParameter)) {
                    //执行sql，还原加解密后的报文
                    return commonUtil.proceed(invocation, mappedStatement, updateParameter);
                }
            }
            if (paramMap.containsKey("et")) {
                Object updateParameter = paramMap.get("et");
                if (commonUtil.needToCrypt(updateParameter)) {
                    //执行sql，还原加解密后的报文
                    return commonUtil.proceed(invocation, mappedStatement, updateParameter);
                }
            }

        } else if (parameter instanceof DefaultSqlSession.StrictMap) {
            return invocation.proceed();
        } else if (commonUtil.needToCrypt(parameter)) {
            //执行sql，还原加解密后的报文
            return commonUtil.proceed(invocation, mappedStatement, parameter);
        }
        //其他场景直接放行
        return invocation.proceed();
    }
}
